package com.zym.init.exception;

import com.zym.init.core.domain.AjaxResult;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.internal.engine.path.PathImpl;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.resource.NoResourceFoundException;

import java.util.Objects;
import java.util.Set;

/**
 * 全局异常处理器
 */
@RestControllerAdvice
@Slf4j
public class GlobalException {

    /**
     * 权限校验异常
     */
    @ExceptionHandler(AccessDeniedException.class)
    public AjaxResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request) {
        log.error("AccessDeniedException：权限校验异常");
        return AjaxResult.permission("没有权限，请联系管理员授权");
    }

    /**
     * 业务异常
     */
    @ExceptionHandler(RuntimeException.class)
    public AjaxResult runtimeExceptionHandler(RuntimeException e) {
        log.error("RuntimeException", e);
        return AjaxResult.error(e.getMessage());
    }

    /**
     * 资源不存在异常
     */
    @ExceptionHandler(NoResourceFoundException.class)
    public AjaxResult noResourceFoundExceptionHandler(NoResourceFoundException e) {
        log.error("NoResourceFoundException", e);
        return AjaxResult.notFound();
    }

    /**
     * 账号被封禁异常
     */
    @ExceptionHandler(BannedException.class)
    public AjaxResult bannedExceptionHandler(BannedException e) {
        log.error("BannedException", e);
        return AjaxResult.permission(e.getMessage());
    }

    /**
     * 业务错误
     */
    @ExceptionHandler(ServiceException.class)
    public AjaxResult businessExceptionHandler(ServiceException e) {
        log.error("ServiceException", e);
        return AjaxResult.serviceError(e.getMessage());
    }

    /**
     * 未知异常
     */
    @ExceptionHandler(Exception.class)
    public AjaxResult exceptionHandler(Exception e) {
        log.error("Exception", e);
        return AjaxResult.error(e.getMessage());
    }

    /**
     * Validator 参数校验异常处理
     */
    @ExceptionHandler(value = BindException.class)
    public AjaxResult handleMethodVoArgumentNotValidException(BindException ex) {
        FieldError err = ex.getFieldError();
        String message = null;
        if (err != null) {
            message = "参数：{".concat(err.getField()).concat("}，").concat(Objects.requireNonNull(err.getDefaultMessage()));
        }
        if (err != null) {
            log.info("{} -> {}", err.getObjectName(), message);
        }
        return AjaxResult.serviceError(message);
    }

    /**
     * Validator 参数校验异常处理
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    public AjaxResult handleMethodArgumentNotValidException(ConstraintViolationException ex) {
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        for (ConstraintViolation<?> constraintViolation : constraintViolations) {
            PathImpl pathImpl = (PathImpl) constraintViolation.getPropertyPath();
            String paramName = pathImpl.getLeafNode().getName();
            String message = "参数：{".concat(paramName).concat("}，").concat(constraintViolation.getMessage());
            log.info("{} -> {} -> {}", constraintViolation.getRootBeanClass().getName(), pathImpl, message);
            return AjaxResult.serviceError(message);
        }
        return AjaxResult.serviceError(ex.getMessage());
    }
}
